package com.yanglei.demo.framework.core.filter;

import com.yanglei.demo.client.OAuth2Client;
import com.yanglei.demo.client.dto.CommonResult;
import com.yanglei.demo.client.dto.oauth2.OAuth2CheckTokenRespDTO;
import com.yanglei.demo.framework.LoginUser;
import com.yanglei.demo.framework.core.util.SecurityUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * OncePerRequestFilter 用于确保每一个请求只执行一次过滤逻辑，解决了重复执行的问题
 * 每次请求过来以后会校验一下用户的token信息是否有效，并根据token创建登录用户
 * Token 过滤器，验证token的有效性
 * 验证通过后，获取得到{@link LoginUser} 信息，并加入到 Spring Security 上下文
 */
@Component
public class TokenAuthenticationFilter extends OncePerRequestFilter {

    @Resource
    private OAuth2Client oauth2Client;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 1、获取访问令牌
        String token = SecurityUtils.obtainAuthorization(request, "Authorization");

        if (StringUtils.hasText(token)) {
            // 2、基于token构建登录用户
            LoginUser loginUser = buildLoginUserByToken(token);
            // 3、设计当前用户
            if (loginUser != null) {
                SecurityUtils.setLoginUser(loginUser, request);
            }
        }

        // 继续执行下面的过滤链
        filterChain.doFilter(request, response);
    }

    private LoginUser buildLoginUserByToken(String token) {
        // 1、去认证服务器去校验token是否过期以及合法
        try {
            CommonResult<OAuth2CheckTokenRespDTO> accessTokenResult = oauth2Client.checkToken(token);
            OAuth2CheckTokenRespDTO accessToken = accessTokenResult.getData();
            if (accessToken == null) {
                return null;
            }
            // 2、构建登录用户
            return new LoginUser().setId(accessToken.getUserId())
                    .setUserType(accessToken.getUserType()).
                    setTenantId(accessToken.getTenantId())
                    .setScopes(accessToken.getScopes())
                    .setAccessToken(accessToken.getAccessToken());
        } catch (Exception e) {
            return null;
        }
    }
}
